package com.github.blanexie.nexusj.controller

import cn.hutool.core.util.IdUtil
import cn.hutool.core.util.URLUtil
import com.github.blanexie.nexusj.bencode.toTorrent
import com.github.blanexie.nexusj.controller.param.Result
import com.github.blanexie.nexusj.controller.param.TorrentQuery
import com.github.blanexie.nexusj.controller.param.UserQuery
import com.github.blanexie.nexusj.support.*
import com.github.blanexie.nexusj.table.*
import com.github.blanexie.nexusj.torrent.domain.valobj.toMap
import io.ktor.application.*
import io.ktor.auth.*
import io.ktor.http.*
import io.ktor.http.content.*
import io.ktor.request.*
import io.ktor.response.*
import io.ktor.routing.*
import org.slf4j.Logger
import org.slf4j.LoggerFactory
import java.io.InputStream
import java.time.LocalDateTime
import kotlin.collections.set

val logger: Logger = LoggerFactory.getLogger("NexusController")!!

fun Route.notAuth() {

    /**
     * 注册
     */
    post("/signup") {
        val signUpParam = call.receive<UserQuery>()
        //TODO 判断验证码是否正确， 判断昵称和邮箱是否已经存在
        val userDO = UserDO()
        userDO.createTime = LocalDateTime.now()
        userDO.email = signUpParam.email!!
        userDO.pwd = signUpParam.pwd!!
        userDO.nick = signUpParam.nick!!
        userDO.avatar = signUpParam.avatar
        userDO.sex = signUpParam.sex!!
        userDO.status = 0
        userDO.updateTime = LocalDateTime.now()
        userDO.save()
        userDO.pwd = ""
        call.respond(Result(body = mapOf("user" to userDO.properties)))
    }

    /**
     * 登录
     */
    post("/login") {
        val loginParam = call.receive<UserQuery>()

        val userDO = UserDO.findByEmailAndPwd(loginParam.email!!, loginParam.pwd!!)
        if (userDO == null) {
            call.respond(Result(403, "登录失败"))
            return@post
        }

        userDO.pwd = ""
        val token = call.application.jwtSign(gson.toJson(userDO.properties))
        call.respond(Result(body = mapOf("token" to token)))
        return@post
    }


    get("/resource") {
        val torrentPath = setting["torrent.path"]
        val queryParameters = call.request.queryParameters
        //校验token 是否正确
        try {
            val token = queryParameters["token"]
            val verify = verifier.verify(token)
        } catch (e: Exception) {
            call.respondBytes(
                bytes = fileCache.getFileBytes("${torrentPath}/b82e1427d012bfbf6e517cf567ac5678.jpeg"),
                contentType = ContentType.Image.JPEG
            )
            return@get
        }

        val filePath = queryParameters["path"]
        val fileBytes = fileCache.getFileBytes("${torrentPath}/$filePath")
        call.response.header("userId", filePath!!)
        call.respondBytes(
            bytes = fileBytes,
            contentType = ContentType.parse(getContentType(filePath))
        )
        return@get
    }

}


fun Route.auth() {


    /**
     * 获取配置信息
     */
    get("/attribute") {
        val queryParameters = call.request.queryParameters
        val type = queryParameters["type"]
        val name = queryParameters["name"]
        val properties = AttributeDO.findByTypeAndName(type!!, name!!)
        if (properties == null) {
            call.respond(Result.NotFound)
        } else {
            call.respond(Result(body = mapOf("$name" to properties.properties)))
        }
        return@get
    }

    /**
     * 搜索查询
     */
    post("/torrent/list") {
        val principal = call.authentication.principal<UserPrincipal>()!!
        val user = principal.user
        val torrentQuery = call.receive<TorrentQuery>()
        val page = TorrentDO.findByQuery(torrentQuery, user.id)
        val ids = page.record.map { it as TorrentDO }.map { it.userId }.toList()
        val userDOs = UserDO.findByIds(ids)
        val list = page.record.map { torrent ->
            val map = mutableMapOf<String, Any?>()
            if (torrent is TorrentDO) {
                val first = userDOs.first { it.id == torrent.userId }

                torrent.properties.forEach { (t, u) -> map[t] = u }
                map["uploadUserName"] = first.nick
            }
            map
        }
        page.record = list
        call.respond(Result(body = mapOf("result" to page)))
        return@post
    }

    get("/user/info") {
        val principal = call.authentication.principal<UserPrincipal>()!!
        val user = principal.user
        val roleDO: RoleDO? = RoleDO.findById(user.roleId)
        if (roleDO == null) {
            call.respond(Result.NotFoundRoleError)
            return@get
        }
        call.respond(Result(body = mapOf("user" to user.properties, "role" to roleDO.properties)))
        return@get
    }

    /**
     * 下载 文件
     */
    get("/download/torrent") {
        val principal = call.authentication.principal<UserPrincipal>()!!
        val user = principal.user
        val id = call.request.queryParameters["id"]!!.toInt()
        val torrentDO = TorrentDO.findById(id)

        if (torrentDO == null) {
            call.respond(Result(code = 404, message = "下载的种子不存在"))
            return@get
        }
        //增加一条userTorrent记录
        var userTorrentDO = UserTorrentDO.findByInfoHashAndUserId(torrentDO.infoHash, user.id)
        if (userTorrentDO == null) {
            userTorrentDO = buildUserTorrent(torrentDO, user.id)
            userTorrentDO.save()
        }

        // 获取下载文件位置
        val torrentPath = setting["torrent.path"]
        val outBytes = fileCache.getFileBytes("${torrentPath}/${torrentDO.infoHash}")

        val fileName = "attachment; filename='${URLUtil.encode(torrentDO.title)}.torrent'; charset=utf-8"
        //返回
        call.response.header("content-disposition", fileName)
        call.respondBytes(
            bytes = outBytes,
            contentType = ContentType.parse("application/x-bittorrent")
        )
    }
    /**
     * 上传文件
     */
    post("/upload/torrent") {
        val principal = call.authentication.principal<UserPrincipal>()!!
        val user = principal.user
        val reqMap = receiveFrom(call.receiveMultipart())
        if (reqMap.containsKey("result")) {
            call.respond(reqMap["result"]!!)
            return@post
        }
        val torrentDO = toTorrent(reqMap)
        torrentDO.userId = user.id
        //查询是否已经存在
        val existTorrentDO = TorrentDO.findByInfoHash(torrentDO.infoHash)
        if (existTorrentDO != null) {
            call.respond(Result(40000, "不要上传重复的文件"))
            return@post
        }
        torrentDO.save()
        call.respond(Result())
        return@post
    }
}

suspend fun receiveFrom(multipartData: MultiPartData): Map<String, Any> {
    val reqMap = hashMapOf<String, Any>()
    val imgSuffix = listOf("jpg", "jpeg", "png")
    val uploadFiles = arrayListOf<UploadFile>()
    reqMap["uploadFiles"] = uploadFiles
    multipartData.forEachPart { partData ->
        when (partData) {
            is PartData.FileItem -> {
                val originalFileName = partData.originalFileName!!
                val suffix = originalFileName.substringAfterLast(".")
                if (suffix in imgSuffix) {
                    val uploadFile =
                        UploadFile(partData.name!!, partData.originalFileName!!, suffix, partData.streamProvider())
                    uploadFiles.add(uploadFile)
                }
            }
            is PartData.FormItem -> {
                reqMap[partData.name!!] = partData.value
            }
            else -> {// 其他类型的不用管}
            }
        }
    }

    return reqMap
}

